﻿using System;
using System.Collections.Generic;

using Moe.ECamel.Common.Entities;
using Moe.ECamel.Common.Security;
using Moe.ECamel.Common.Utils;
using Moe.ECamel.Server.Services;

namespace Moe.ECamel.Server.Demo
{
	public class DemoDataGenerator
	{
		private static readonly Random _random = new Random();

		public static void GenerateAll()
		{
			IEnumerable<Library> libraries = GenerateLibraries();

			IEnumerable<Employee> employees = GenerateEmployees(libraries);
			IEnumerable<Customer> customers = GenerateCustomers(libraries);

			IEnumerable<Subscription> subscriptions = GenerateSubscriptions(customers);

			IEnumerable<Item> items = GenerateContent();
			GenerateInventory(items, libraries);
		}

		private static IEnumerable<Library> GenerateLibraries()
		{
			string openingHours = "א-ה: 08:00-18:00" + Environment.NewLine +
			                      "ו, ערבי חג: 08:00-13:00" + Environment.NewLine +
			                      "שבתות וחגים - סגור";

			var libraries = new Library[] 
          	{ 
          		new Library {LibraryTypeId = 1, Active = true, 
          		             LibraryName = "צפון",
          		             Address = "חיפה", Telephone = "04-555-1000", Fax = "04-555-1001",
          		             OpeningHours = openingHours},
          		new Library { LibraryTypeId = 1, Active = true, 
          		              LibraryName = "מרכז",
          		              Address = "ירושלים", Telephone="02-555-1000", Fax="02-555-1001", 
          		              OpeningHours = openingHours},
          		new Library { LibraryTypeId = 1, Active=true, 
          		              LibraryName = "דרום",
          		              Address = "באר-שבע", Telephone = "08-555-1000", Fax = "08-555-1001", 
          		              OpeningHours = openingHours},
          		new Library {
          		            	LibraryTypeId =2, Active=true, 
          		            	LibraryName="חיפה", ParentLibraryId=1, 
          		            	Address="חיפה", Telephone="04-555-2000", Fax="04-555-2001",
          		            	OpeningHours=openingHours},
          		new Library {
          		            	LibraryTypeId =2, Active=true, 
          		            	LibraryName="תל-אביב", ParentLibraryId=2, 
          		            	Address="תל-אביב", Telephone="03-555-2000", Fax="03-555-2001",
          		            	OpeningHours=openingHours},
          		new Library {
          		            	LibraryTypeId =2, Active=true, 
          		            	LibraryName="באר-שבע", ParentLibraryId=3, 
          		            	Address="באר-שבע", Telephone="08-555-2000", Fax="08-555-2001",
          		            	OpeningHours=openingHours},
          		new Library {
          		            	LibraryTypeId =3, Active=true, 
          		            	LibraryName="הדר יוסף", ParentLibraryId=5, 
          		            	Address="הדר יוסף 17", Telephone="03-555-2100", Fax="03-555-2101",
          		            	OpeningHours=openingHours},
          		new Library {
          		            	LibraryTypeId =3, Active=true, 
          		            	LibraryName="רמת אביב ג'", ParentLibraryId=5, 
          		            	Address="קניון רמת אביב", Telephone="03-555-2200", Fax="03-555-2201",
          		            	OpeningHours=openingHours},
          		new Library {
          		            	LibraryTypeId =3, Active=true, 
          		            	LibraryName="יד אליהו", ParentLibraryId=5, 
          		            	Address="היכל נוקיה", Telephone="03-555-2300", Fax="03-555-2301",
          		            	OpeningHours=openingHours},
          	};

			using (var si = new LibraryService())
			{
				si.CreateLibraries(libraries);
			}

			return libraries;
		}
		
		private static IEnumerable<Employee> GenerateEmployees(IEnumerable<Library> libraries)
		{
			var employees = new List<Employee>();
			int employeeCounter = 1;
			string[] firstNames = new string[] { "איציק", "קרן", "שלום", "טל", "מיכל" };
			string[] lastNames = new string[] { "לוי", "כהן", "בוזגלו", "ישראלי", "מנדלבאום" };

			foreach (var library in libraries)
			{
				for (int i = 0; i < 5; i++)
				{
					Employee employee = new Employee();
					employee.LibraryId = library.LibraryId;
					employee.IsActive = true;
					employee.User = new User();
					employee.User.SetDefaultValues();
					employee.User.Username = "u" + employeeCounter++.ToString().PadLeft(4, '0');
					ECamelPasswordHasher.GenerateDefaultPassword(employee.User);
					employee.User.FirstName = GetRandomItem(firstNames);
					employee.User.LastName = GetRandomItem(lastNames);
					employee.User.EmailAddress = employee.Username + "@moe.gov.il";
					employee.User.Telephone = library.Telephone;
					if (i == 0)
					{
						employee.Salary = 5000;
						employee.User.UserRoles.Add(new UserRoles { User = employee.User, RoleId = Roles.Manager });
					}
					else
						employee.Salary = 4000;
					employees.Add(employee);
				}
			}

			using (var si = new EmployeeService())
			{
				si.CreateEmployees(employees);
			}

			return employees;
		}
		private static IEnumerable<Customer> GenerateCustomers(IEnumerable<Library> libraries)
		{
			var customers = new List<Customer>();

			int customersCounter = 1;
			string[] customerFirstNames = new string[] { "עודד", "צביקה", "פיני", "דיויד", "אפי" };
			string[] customerLastNames = new string[] { "קטש", "שרף", "גרשון", "בלאט", "בירנבוים" };

			foreach (var library in libraries)
			{
				for (int i = 0; i < 5; i++)
				{
					Customer customer = new Customer();
					customer.LibraryId = library.LibraryId;
					customer.User = new User();
					customer.User.SetDefaultValues();
					customer.User.Username = "c" + customersCounter++.ToString().PadLeft(4, '0');
					ECamelPasswordHasher.GenerateDefaultPassword(customer.User);
					customer.User.FirstName = GetRandomItem(customerFirstNames);
					customer.User.LastName = GetRandomItem(customerLastNames);
					customers.Add(customer);
				}
			}

			using (var si = new CustomerService())
			{
				si.CreateCustomers(customers);
			}

			return customers;
		}

		private static IEnumerable<Subscription> GenerateSubscriptions(IEnumerable<Customer> customers)
		{
			var subscriptions = new List<Subscription>();

			using (var si = new SubscriptionService())
			{
				// Get list of subscription types:
				var subscriptionTypes = si.GetSubscriptionTypes();
				var today = SystemContainer.Clock.Today;

				foreach (var customer in customers)
				{
					// Select subscription type at random:
					SubscriptionType subscriptionType = subscriptionTypes[_random.Next(subscriptionTypes.Count)];
					// Create and initialize a new subscription:
					var subscription = new Subscription { CustomerId = customer.CustomerId };
					int days = _random.Next(100);
					subscription.InitializeNewSubscription(subscriptionType, today.AddDays(days));
					// Set item types quantities at random:
					foreach (var subscriptionItemTypeInfo in subscription.SubscriptionItemTypeInfos)
						subscriptionItemTypeInfo.Quantity = _random.Next(0, 5);
					// Add subscription to list:
					subscriptions.Add(subscription);
				}

				si.CreateSubscriptions(subscriptions);
			}

			return subscriptions;
		}

		private static IEnumerable<Item> GenerateContent()
		{
			var items = new List<Item>();
			// Add Books:
			items.Add(CreateBook(1, "אם יש גן עדן", "רון לשם", "זמורה ביתן", "מלחמה", "320", "2005"));
			items.Add(CreateBook(2, "שעות מתות", "אורי אדלמן", "כתר", "מתח", "505", "2004"));
			items.Add(CreateBook(3, "קונצ'רטו למרגל ולתזמורת", "אורי אדלמן", "כתר", "מתח", "190", "1993"));
			items.Add(CreateBook(4, "האזרח י.", "עפר קניספל", "עם עובד", "הומור", "176", "2001"));
			items.Add(CreateBook(5, "ספר משפחתי", "אפרים קישון", "מעריב", "הומור", "342", "1980"));
			items.Add(CreateBook(6, "The Hobbit", "J. R. R. Tolkien", "George Allen & Unwin", "Fantasy novel", "310", "1937"));
			items.Add(CreateBook(7, "The Return Of The King", "J. R. R. Tolkien", "George Allen & Unwin", "Fantasy", null, "1955"));
			items.Add(CreateBook(8, "The Catcher in the Rye", "J. D. Salinger", "Little, Brown and Company", "Novel", "276", "1951"));
			items.Add(CreateBook(9, "Jurassic Park", "Michael Crichton", "Alfred A. Knopf", "Science Fiction", "398", "1990"));
			items.Add(CreateBook(10, "The Lion, the Witch and the Wardrobe", "C.S. Lewis", "Geoffrey Bles", "Fantasy", "208", "1950"));
			// Add audio CDs:
			items.Add(CreateAudioCD(1, "פצעים ונשיקות", "מוניקה סקס", "רוק", "43:12", "1995", "13"));
			items.Add(CreateAudioCD(2, "נגיעות", "ברי סחרוף", "רוק", null, "1998", "12"));
			items.Add(CreateAudioCD(3, "חם על הירח", "ברי סחרוף", "רוק", "52:00", "1996", "11"));
			items.Add(CreateAudioCD(4, "סוף עונת התפוזים", "תמוז", "רוק", "50:14", "1976", "8"));
			items.Add(CreateAudioCD(5, "עד הקצה", "דנה ברגר", "רוק", "39:38", "2000", "10"));
			items.Add(CreateAudioCD(6, "Sgt. Pepper's Lonely Hearts Club Band", "Beatles, The", "Rock", "39:42", "1967", "13"));
			items.Add(CreateAudioCD(7, "Yellow Submarine", "Beatles, The", "Rock", "40:12", "1969", "13"));
			items.Add(CreateAudioCD(8, "The Wall", "Pink Floyd", "Progressive Rock", "81:09", "1979", "26"));
			items.Add(CreateAudioCD(9, "A Night at the Opera", "Queen", "Rock", "43:10", "1975", "12"));
			items.Add(CreateAudioCD(10, "Hot Fuss", "Killers, The", "Indie Rock", "45:39", "2004", "11"));
			// Add Videos:
			items.Add(CreateVideoCassette(1, "גבעת חלפון אינה עונה", "אסי דיין", "ישראל פוליאקוב", "שייקה לוי", "92", "1976"));
			items.Add(CreateVideoCassette(2, "תעלת בלאומילך", "אפרים קישון", "בומבה צור", "שייקה אופיר", "90", "1969"));
			items.Add(CreateVideoCassette(3, "ואלס עם באשיר", "ארי פולמן", "ארי פולמן", "מיקי לאון", "90", "2008"));
			items.Add(CreateVideoCassette(4, "סיפור גדול", "שרון מימון", "איציק כהן", "עירית קפלן", "90", "2009"));
			items.Add(CreateVideoCassette(5, "הקיץ של אביה", "אלי כהן", "גילה אלמגור", "אביטל דיקר", "95", "1988"));
			items.Add(CreateVideoCassette(6, "Fight Club", "David Fincher", "Edward Norton", "Brad Pitt", "139", "1999"));
			items.Add(CreateVideoCassette(7, "The Matrix", "Andy & Lana Wachowski", "Keanu Reeves", "Laurence Fishburne", "136", "1999"));
			items.Add(CreateVideoCassette(8, "eXistenZ", "David Cronenberg", "Jennifer Jason Leigh", "Jude Law", "97", "1999"));
			items.Add(CreateVideoCassette(9, "Inception", "Christopher Nolan", "Leonardo DiCaprio", "Ellen Page", "148", "2010"));
			items.Add(CreateVideoCassette(10, "The Dark Knight", "Christopher Nolan", "Christian Bale", "Heath Ledger", "152", "2008"));

			using (var si = new ItemService())
			{
				si.CreateItems(items);
			}

			return items;
		}
		private static Item CreateBook(int i, String title, params string[] properties)
		{
			return CreateItem(1, title, "BK-" + i.ToString("0000"), properties);
		}
		private static Item CreateAudioCD(int i, String title, params string[] properties)
		{
			return CreateItem(2, title, "CD-" + i.ToString("0000"), properties);
		}
		private static Item CreateVideoCassette(int i, String title, params string[] properties)
		{
			return CreateItem(3, title, "VC-" + i.ToString("0000"), properties);
		}
		private static Item CreateItem(int itemTypeId, String title, String catalogNumber, params string[] properties)
		{
			Item item = new Item { ItemTypeId = itemTypeId, Title = title, CatalogNumber = catalogNumber };

			int firstPropertyId = (itemTypeId - 1) * 5 + 1;
			for (int i = 0; i < properties.Length; i++)
				if (properties[i] != null)
					item.ItemProperties.Add(new ItemProperty { ItemPropertyTypeId = firstPropertyId + i, Value = properties[i] });

			return item;
		}

		private static void GenerateInventory(IEnumerable<Item> items, IEnumerable<Library> libraries)
		{
			var inventoryList = new List<Inventory>();
			foreach (var item in items)
			{
				foreach (var library in libraries)
				{
					int copies = _random.Next(9);
					for (int i = 0; i < copies; i++)
						inventoryList.Add(new Inventory {ItemId = item.ItemId, LibraryId = library.LibraryId, IsAvailable = true, IsActive = true});
				}
			}

			using (var si = new InventoryService())
			{
				si.AddInventoryList(inventoryList);
			}
		}

		private static T GetRandomItem<T>(T[] array)
		{
			return array[_random.Next(array.Length)];
		}
	}
}
